//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Collections
{
    class FixedArrayDictionary<TValue>: IFrugalDictionary<TValue> where TValue: class
    {
        internal const int Capacity = 128;
        public FixedArrayDictionary(int minValue)
        {
            this._minValue = minValue;
            Contract.Assert(minValue % Capacity == 0);
        }

        readonly int _minValue;
        int _count;
        #region IFrugalDictionary<TValue> Members

        public int Count
        {
            get { return _count ; }
        }

        public bool Remove(int key)
        {
            Contract.Ensures(!this.ContainsKey (key));
            int diff = key - _minValue;
            if (diff < 0 || diff >= Capacity)
                return false;
            if (!_usedKey[diff])
                return false;
            _usedKey[diff] = false;
            _values[diff] = default(TValue);
            _count--;
            return true;
        }

        public bool ContainsKey(int key)
        {
            TValue value;
            return TryGetValue(key, out value);
        }

        public IEnumerator<int> GetEnumerator()
        {
            for (int i = 0; i < Capacity; i++)
            {
                if (_usedKey[i])
                    yield return _minValue + i;
            }
        }

        public bool TryGetValue(int key, out TValue value)
        {
            int diff = key - _minValue;
            if (diff < 0 || diff >= Capacity)
            {
                value = default(TValue);
                return false;
            }
            if (_usedKey[diff])
            {
                value = _values[diff];
                return true;
            }
            value = default(TValue);
            return false;
        }

        public IFrugalDictionary<TValue> TryAddValue(int key, TValue value)
        {
#if DEBUG
            Contract.Requires(!this.ContainsKey(key));
#endif
            int diff = key - _minValue;
            if (diff < 0 || diff >= Capacity)
            {
                return new ClusteredDictionary<TValue>();
            }
            bool alreadyThere = _usedKey[diff];
            if (alreadyThere)
                throw new ArgumentException();
            if (diff < 0)
                throw new ArgumentException();
            if (diff >= Capacity)
                throw new ArgumentException();
            _values[diff] = value;
            _usedKey[diff] = true;
            _count++;
            return null;
        }

        readonly TValue[] _values = new TValue[Capacity];
        readonly bool[] _usedKey = new bool[Capacity];

        #endregion
    }
}
